<?php
/**
 * Created by PhpStorm.
 * User: peter
 * Date: 2018/6/16
 * Time: 下午2:45
 */

namespace app\mall\logic;


use app\model\Member;
use app\model\WeChat;
use extend\Functions;
use extend\STATUS_CODE;
use extend\WeChatTemplateMessage;
use think\facade\Log;
use think\facade\Request;

class Sign
{
    /**
     * @purpose 获取用户token
     * @param string $code
     * @param string $token
     * @param string $invitaion
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function getToken(
        string $code = '',
        string $token = '',
        string $invitation = ''): array
    {
        // 微信授权优先
        if ($code) {
            return self::sign($code, $invitation);
        }
        // token 优先
        if ($token) {
            return self::getTokenByToken($token);
        }
        return Functions::result(
            STATUS_CODE::PARAMETER_ERROR,
            '参数错误!'
        );
    }

    /**
     * @purpose 通过token获取新的token
     * @param string $token
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private static function getTokenByToken(string $token): array
    {
        $model       = new Member();
        $member_info = $model
            ->where(['token' => $token])
            ->field('uid,now_ip,now_time')
            ->find();
        if (!$member_info) {
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::EXPIRED_TOKEN
                ],
                'expired token!'
            );
        }
        $data                    = [];
        $data['last_login_ip']   = $member_info->now_ip;
        $data['last_login_time'] = $member_info->now_time;
        $data['now_time']        = time();
        $data['now_ip']          = Request::ip();
        $data['token']           = strtolower(Functions::getUUID());
        RE_TOKEN:
        $data['token'] = strtolower(Functions::getUUID());
        if ($model->total(['token' => $data['token']])) {
            goto RE_TOKEN;
        }
        $result = $model->save($data, ['uid' => $member_info->uid]);

        if ($result) {
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token' => $data['token']
                ],
                'success'
            );
        }
        return Functions::result(
            STATUS_CODE::FAIL,
            '登录失败!'
        );

    }

    /**
     * @purpose 通过微信授权登录或注册
     * @param string $code
     * @param string $invitation
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    private static function sign(string $code, string $invitation): array
    {
        // 获取openid或者unionid
        $we_chat_user_info = self::getWeChatUserInfo($code);
        // 获取失败则直接返回
        if (isset($we_chat_user_info['code'])) {
            return $we_chat_user_info;
        }
        $unionid = '';
        $openid  = $we_chat_user_info['openid'];
        if (isset($we_chat_user_info['unionid'])) {
            $unionid = $we_chat_user_info['unionid'];
        }
        $wechat = new WeChat();
        $member = new Member();
        $where  = [];
        if ($openid) {
            $where['openid'] = $openid;
        }
        if ($unionid) {
            $where['unionid'] = $unionid;
        }
        $member_info = [];
        if (!empty($where)) {
            $member_info = $wechat
                ->with('member')
                ->whereOr($where)
                ->find();
        }
        // 没有查询到信息则进行注册
        if (!$member_info) {
            // 组装用户数据
            $member_data = [];
            // 生成用户uuid
            $member_data['uuid'] = Functions::getUUID();
            RE_UUID:
            $member_data['uuid'] = Functions::getUUID();
            if ($member->total(['uuid' => $member_data['uuid']]) > 0) {
                goto RE_UUID;
            }
            $member_data['token'] = strtolower(Functions::getUUID());
            RE_TOKEN:
            $member_data['token'] = strtolower(Functions::getUUID());
            if ($member->total(['token' => $member_data['token']]) > 0) {
                goto RE_TOKEN;
            }
            $member_data['nickname'] = $we_chat_user_info['nickname'];
            // 生成用户邀请码
            $member_data['invitation'] = Functions::create_random_str(6);
            RE_INVITATION:
            $member_data['invitation'] = Functions::create_random_str(6);
            if ($member->total(['invitation' => $member_data['invitation']]) > 0) {
                goto RE_INVITATION;
            }
            // 检测邀请码是否有效,
            if ($member->total(['invitation' => $invitation]) > 0) {
                $member_data['invitation_from'] = $invitation;
            }
            $member_data['create_ip']       = Request::ip();
            $member_data['now_ip']          = Request::ip();
            $member_data['last_login_ip']   = Request::ip();
            $member_data['now_time']        = time();
            $member_data['last_login_time'] = time();
            if (isset($we_chat_user_info['headimgurl'])) {
                $member_data['avatar'] = $we_chat_user_info['headimgurl'];
            }
            if (isset($we_chat_user_info['sex'])) {
                $member_data['sex'] = $we_chat_user_info['sex'];
            }
            // 组装微信授权数据
            $wechat_data              = [];
            $wechat_data['openid']    = $openid;
            $wechat_data['unionid']   = $unionid;
            $wechat_data['subscribe'] = $we_chat_user_info['subscribe'];
            if (isset($we_chat_user_info['subscribe_time'])) {
                $wechat_data['subscribe_time'] = $we_chat_user_info['subscribe_time'];
            }
            if (isset($we_chat_user_info['subscribe_scene'])) {
                $wechat_data['subscribe_scene'] = $we_chat_user_info['subscribe_scene'];
            }
            $member->startTrans();
            $result_member      = $member
                ->data($member_data)
                ->save();
            $wechat_data['uid'] = $member->uid;
            $result_wechat      = $wechat
                ->data($wechat_data)
                ->save();
            if ($result_member && $result_wechat) {
                $member->commit();
                self::sendWechatMessageForInvitation($member->uid);
                self::checkParentIsUpgradeAgent($member->uid);
                return Functions::result(
                    STATUS_CODE::SUCCESS,
                    [
                        'status' => STATUS_CODE::SUCCESS,
                        'token' => $member_data['token']
                    ]
                );
            }
            $member->rollback();
            return Functions::result(
                STATUS_CODE::CREATE_FAIL,
                '注册失败!'
            );
        }
        // 查询到信息则进行登录
        $data                    = [];
        $data['last_login_ip']   = $member_info->now_ip;
        $data['last_login_time'] = $member_info->now_time;
        $data['now_time']        = time();
        $data['now_ip']          = Request::ip();
        $data['avatar']          = $we_chat_user_info['headimgurl'];
        $data['nickname']        = $we_chat_user_info['nickname'];
        $data['sex']             = $we_chat_user_info['sex'];
        $data['token']           = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $data['token'] = strtolower(Functions::getUUID());
        if ($member->total(['token' => $data['token']])) {
            goto RE_LOGIN_TOKEN;
        }
        $result = $member
            ->save($data, ['uid' => $member_info->uid]);
        if ($result) {
            // 检测当前微信用户信息是否有unionid 如果有则更新到授权表里面去
//            if ($unionid && !$member_info->unionid) {
            $wechat_data              = [];
            $wechat_data['unionid']   = $unionid;
            $wechat_data['subscribe'] = $we_chat_user_info['subscribe'];
            if (isset($we_chat_user_info['subscribe_time'])) {
                $wechat_data['subscribe_time'] = $we_chat_user_info['subscribe_time'];
            }
            if (isset($we_chat_user_info['subscribe_scene'])) {
                $wechat_data['subscribe_scene'] = $we_chat_user_info['subscribe_scene'];
            }
            $wechat->save(
                $wechat_data,
                ['uid' => $member_info->uid]);
//            }
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token' => $data['token']
                ]
            );
        }
        return Functions::result(
            STATUS_CODE::UPDATE_FAIL,
            '登录失败!'
        );
    }

    /**
     * @purpose 检测当前用户父级是否满足升级代理商条件
     * @param int $uid
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private static function checkParentIsUpgradeAgent(int $uid)
    {
        $member      = new Member();
        $member_info = $member
            ->where('uid', $uid)
            ->field('uid,invitation,invitation_from')
            ->find();
        // 如果用户不存在则停止
        if (!$member_info) {
            return false;
        }
        // 如果用户没有父级则停止
        if ($member_info->invitation_from === 'self') {
            return false;
        }
        $parent = $member
            ->where('invitation', $member_info->invitation_from)
            ->field('uid,invitation,agent,agent_end_time')
            ->find();
        // 如果父级不存在则停止
        if (!$parent) {
            return false;
        }
        // 如果父级已经是代理则停止
        if ($parent->agent === 2) {
            return false;
        }
        // 如果父级已经曾经是代理商则停止
        if ($parent->agent_end_time > 0) {
            return false;
        }
        return (bool)$member
            ->save([
                'agent' => 2,
                'agent_end_time' => strtotime(date('Y-m-d', (time() + 3600 * 24 * 365)) . ' 00:00:00')
            ], ['uid' => $parent->uid]);
    }

    /**
     * @purpose 注册时给上级发送模板消息
     * @param $uid
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private static function sendWechatMessageForInvitation($uid)
    {
        /* @param array $data = [
         *  'openid' => '',
         *  'level'  => '一级|二级',
         *  'nickname'  => 'peter',
         *  'create_date'  => 'peter',
         *  'first'  => 45,
         *  'second'  => 11,
         * ]*/
        $member = new Member();
        // 获取上级邀请码
        $info = $member
            ->where('uid', $uid)
            ->field('nickname,invitation_from,FROM_UNIXTIME(create_at, \'%Y-%m-%d %H:%i:%s\') as create_date')
            ->find();
        if ($info->invitation_from !== 'self') {
            $parent      = $member
                ->alias('m')
                ->join('wechat w', 'm.uid=w.uid')
                ->where(['m.invitation' => $info->invitation_from])
                ->field('m.uid,m.invitation,m.invitation_from,w.openid,w.unionid')
                ->find();
            $parent_data = [
                'openid' => $parent->openid,
                'level' => '一级',
                'nickname' => $info->nickname,
                'create_date' => $info->create_date,
            ];
            $total       = \app\mall\logic\Member::invitationTotal($parent->invitation);
            $parent_data = array_merge($parent_data, $total['data']);
            WeChatTemplateMessage::invitationRegister($parent_data);
            if ($parent->invitation_from !== 'self') {
                $grandpa      = $member
                    ->alias('m')
                    ->join('wechat w', 'm.uid=w.uid')
                    ->where(['m.invitation' => $parent->invitation_from])
                    ->field('m.uid,m.invitation,m.invitation_from,w.openid,w.unionid')
                    ->find();
                $grandpa_data = [
                    'openid' => $grandpa->openid,
                    'level' => '二级',
                    'nickname' => $info->nickname,
                    'create_date' => $info->create_date,
                ];
                $total        = \app\mall\logic\Member::invitationTotal($grandpa->invitation);
                $grandpa_data = array_merge($grandpa_data, $total['data']);
                WeChatTemplateMessage::invitationRegister($grandpa_data);
            }
        }
    }

    /**
     * @purpose 获取微信用户的AccessToken
     * @param $code
     */
    private static function getAccessToken($code)
    {
        $url    = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . config('app.wechat.appid') . '&secret=' . config('app.wechat.secret') . '&code=' . $code . '&grant_type=authorization_code';
        $result = \Requests::get($url);
        $result = json_decode($result->body, true);
        return $result;
    }

    /**
     * @purpose 获取微信用户的用户信息
     * @param $code
     * @return array|mixed|\Requests_Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    private static function getWeChatUserInfo($code)
    {
        $accessTokenInfo = self::getAccessToken($code);
        if (isset($accessTokenInfo['errcode'])) {
            Log::write('wechat_access_token:' . json_encode($accessTokenInfo), 'error');
            return Functions::result(
                $accessTokenInfo['errcode'],
                $accessTokenInfo,
                $accessTokenInfo['errmsg']
            );
        }
        // 当用户没有关注公众号时不能获取到用户的基本信息,所以这里还是要利用网页授权来获取,同时获取利用全局access_token来获取用户是否关注公众号,然后合并数据
        $accessToken = Functions::getAccessToken();
        $openId      = $accessTokenInfo['openid'];
        $url1        = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $accessToken . '&openid=' . $openId . '&lang=zh_CN';
        $url         = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $accessTokenInfo['access_token'] . '&openid=' . $openId . '&lang=zh_CN';
        $result1     = \Requests::get($url1);
        $result      = \Requests::get($url);
        $result1     = json_decode($result1->body, true);
        $result      = json_decode($result->body, true);
        $result      = array_merge($result1, $result);
        if (isset($result['errcode'])) {
            Log::write('wechat_user_info:' . json_encode($result), 'error');
            return Functions::result(
                $result['errcode'],
                $result,
                $result['errmsg']
            );
        }
        return $result;
    }
}